<?php 
// @ini_set('mssql.datetimeconvert','0');
// @ini_set("mssql.textsize",200000);
// @ini_set("mssql.textlimit",200000);
use	Workerman\Worker; 
require_once	'./Workerman/Autoloader.php';
require_once	'./mysql/src/Connection.php';

//	初始化一个worker容器，监听1234端口
$worker	=	new	Worker('tcp://0.0.0.0:2000');
/*
 *	注意这里进程数必须设置为1，否则会报端口占用错误
 *	(php	7可以设置进程数大于1，前提是$inner_text_worker->reusePort=true)
 */
$worker->count = 1;

$worker->onConnect = function($connection){
	log_record('【'.date("Y-m-d H:i:s").' ip：'.$connection->getRemoteIp().'】：'.'进行连接'."\r\n");
};

//新增加一个属性，用来保存uid到connection的映射 
$worker->uidConnections	= array();
//新增加一个属性，用来保存php到connection的映射 
//$worker->phpConnections	= array();
//	worker进程启动后创建一个text	Worker以便打开一个内部通讯端口
$worker->onWorkerStart	= function($worker){
	//	将db实例存储在全局变量中(也可以存储在某类的静态成员中)
	global $db;
	global $worker;
	$db  = new \Workerman\MySQL\Connection('112.74.84.200','3306','root','Tosky2016', 'dream_flower'); 
	//	开启一个内部端口，方便内部系统推送数据，Text协议格式	文本+换行符
	$inner_text_worker	= new Worker('text://0.0.0.0:2001');
	//该端口有数据发来时，触发函数
	$inner_text_worker->onMessage = function($connection,$buffer){
		global $worker;
		//	$data转化成数组格式，里面有uid，表示向那个uid的页面推送数据
		$data = decodeJson($buffer,true);
		$uid = $data['uid'];
		$value = $data['value'];
		if(isset($worker->uidConnections[$uid])){
			//通过workerman，向uid的页面推送数据
			$ret = sendMessageByUid($uid,$value."\n");
			//返回推送结果
			//$connection->send($ret?'ok':'fail');
			//保存PHP端的连接信息
			$_SESSION['connection'][$uid] = $connection;
		}else{
			$connection->send('2');
			log_record('【'.date("Y-m-d H:i:s").' ip：'.$connection->getRemoteIp().'】：'.'uid为'.$uid.'的硬件设备没连接'."\r\n");
		}
	};
	//	##	执行监听	##
	$inner_text_worker->listen();
};
//当有客户端发来消息时执行的回调函数 
$worker->onMessage = function($connection,$data){
	global $worker;
	global $db;
	if(analyJson($data)){
		$datas = trim($data);
		$datas = decodeJson($datas);
		//	判断当前客户端是否已经验证,既是否设置了uid
		// var_dump($data);
		if(!isset($connection->uid) || isset($datas['uid'])){
			if(!is2string($datas['uid'])){
				log_record('【'.date("Y-m-d H:i:s").' ip：'.$connection->getRemoteIp().'】：'.'uid输入不规范！'."\r\n");
				return;
			}else{
				$insert['uid'] = $insert2['uid'] = $datas['uid'];//识别id
				$insert['ip'] = $insert2['ip'] = $connection->getRemoteIp();//客户端ip
				$result = $db->select('ip')->from('dream_connect_info')->where("uid = '".$insert2['uid']."'")->row();
				//是否重新连接
				if($result){
					$connection->uid = $datas['uid'];
					$worker->uidConnections[$connection->uid] = $connection;
					$ret = sendMessageByUid($connection->uid,'{11}'."\n");
					//返回推送结果，处理成日记
					$ret?(log_record('【'.date("Y-m-d H:i:s").' ip：'.$connection->getRemoteIp().'】：硬件设备uid为'.$datas['uid'].'，重新连接成功，并发送{11}给硬件！'."\r\n")):(log_record('【'.date("Y-m-d H:i:s").' ip：'.$connection->getRemoteIp().'】：硬件设备uid为'.$datas['uid'].'重新连接成功，发送{11}给硬件失败！'."\r\n"));
					return;
				}else{
					$insert2['switch'] = '00';//00关，10开灯，01抽水，11双开
					$insert2['item'] = 'flower';
					$insert2['automatic'] = '12';//12关，13开
					$insert2['adddate'] = date("Y-m-d H:i:s");
					$ok2 = $db->insert('dream_datas')->cols($insert2)->query();
					$ok1 = $db->insert('dream_connect_info')->cols($insert)->query();
					if($ok1 && $ok2){
						//保存uid标识
						$connection->uid = $datas['uid'];
						/*	保存uid到connection的映射，这样可以方便的通过uid查找connection
						*	实现针对特定uid推送数据
						*/
						$worker->uidConnections[$connection->uid] = $connection;
						$ret = sendMessageByUid($connection->uid,'{11}'."\n");
						//返回推送结果
						$ret?(log_record('【'.date("Y-m-d H:i:s").' ip：'.$connection->getRemoteIp().'】：硬件设备uid为'.$datas['uid'].'，第一次连接成功，并发送{11}给硬件！'."\r\n")):(log_record('【'.date("Y-m-d H:i:s").' ip：'.$connection->getRemoteIp().'】：硬件设备uid为'.$datas['uid'].'，第一次连接成功，发送{11}给硬件失败！'."\r\n"));
					}else log_record('【'.date("Y-m-d H:i:s").' ip：'.$connection->getRemoteIp().'】：'.'第一次连接时mysql出错，硬件设备uid为'.$datas['uid']."\r\n");
					
				}
			}
		}else{
			//返回执行状态
			if(isset($datas['status'])){
				sendMessageToPhp($connection->uid,$datas['status']."\n");
			}else{
				//接收环境参数
				$value['params'] = encodeJson($datas);
				$value['editdate'] = date("Y-m-d H:i:s");
				$ok	= $db->update('dream_datas')->cols($value)->where("uid = '".$connection->uid."'")->query();
				if($ok) log_record('【'.date("Y-m-d H:i:s").' ip：'.$connection->getRemoteIp().'】：'.'数据保存成功，硬件设备uid为'.$connection->uid."\r\n");
				else log_record('【'.date("Y-m-d H:i:s").' ip：'.$connection->getRemoteIp().'】：'.'数据保存失败，硬件设备uid为'.$connection->uid."\r\n");
			}
		}
	}else if(isset($connection->uid)){
		if(isset($_SESSION[$connection->uid]['image']))
			$image = $_SESSION[$connection->uid]['image'];
		else
			$image = '';
		$icon_hex = bin2hex($data);
		$image .= $icon_hex;
		$_SESSION[$connection->uid]['image'] = $image;
		//截取前五和后五位
		$substr_h = substr($image, 0,4);
		$substr_f = substr($image,-5);
		if($substr_f == '00000' && $substr_h == 'ffd8'){
			$search = array(" ","　","\n","\r","\t");
			$replace = array("","","","","");
			$str = str_replace($search, $replace, $image);
	    	$imgdata = pack('H*',$str);
	    	$savePath = './Public/share/images/uploads/'; // 设置附件上传（子）目录
	    	if(!file_exists($savePath))
	    		//检查是否有该文件夹，如果没有就创建，并给予最高权限
				mkdir($savePath, 0700);
			$image_name = time().'.jpg';
			$new_file = $savePath.$image_name;
			if (file_put_contents($new_file, $imgdata)){
				$value['image'] = 'share/images/uploads/'.$image_name;
				$value['editdate'] = date("Y-m-d H:i:s");
				$ok	= $db->update('dream_datas')->cols($value)->where("uid = '".$connection->uid."'")->query();
				if($ok){
					unset($_SESSION[$connection->uid]['image']);
					log_record('【'.date("Y-m-d H:i:s").' ip：'.$connection->getRemoteIp().'】：'.'图片路径保存到数据库成功，硬件设备uid为'.$connection->uid."\r\n");
				}else log_record('【'.date("Y-m-d H:i:s").' ip：'.$connection->getRemoteIp().'】：'.'图片路劲保存到数据库失败，硬件设备uid为'.$connection->uid."\r\n");

			}else log_record('【'.date("Y-m-d H:i:s").' ip：'.$connection->getRemoteIp().'】：'.'图片保存失败，硬件设备uid为'.$connection->uid."\r\n");
		}
	}else log_record('【'.date("Y-m-d H:i:s").' ip：'.$connection->getRemoteIp().'】：非法访问'."\r\n");
	return;
};
//	当有客户端连接断开时
$worker->onClose = function($connection){
	global $worker;
	global $db;
	if(isset($connection->uid)){
		//删除客户端的连接数据
		//$result = $db->delete('workerman')->where("uid = $connection->uid")->query();
		//if($result>0) echo "删除成功！"."\n";
		echo $connection->uid.'close'."\n";
		//	连接断开时删除映射
		unset($worker->uidConnections[$connection->uid]);
		if(isset($_SESSION['connection'][$connection->uid]))
			unset($_SESSION['connection'][$connection->uid]);
	}
};


//	向所有验证的用户推送数据 
function broadcast($message){
	global	$worker;
	foreach($worker->uidConnections	as	$connection){
		$connection->send($message);
	}
}

//	针对uid推送数据
function sendMessageByUid($uid,	$message){
	global	$worker;
	if(isset($worker->uidConnections["$uid"])){
		$connection	= $worker->uidConnections["$uid"];
		$connection->send($message);
		return	true;
	}
	return	false;
}

//	针对uid推送数据
function sendMessageToPhp($uid,	$message){
	global	$worker;
	if(isset($_SESSION['connection']["$uid"])){
		$connection	= $_SESSION['connection']["$uid"];
		$connection->send($message);
		return	true;
	}
	return	false;
}

/**
 * 判断参数是否为字符串
 * @param mixed $str 要判断的变量
 * @param string $filter 条件,多个逗号分隔,如"c,e,n"(如-> n:数字, c:中文, e:英文)
 * @param string $other 其它字符 (如:_*%)
 */
function is2string($str='',$filter='',$other=''){
    if($str=='')
        return false;
    if(!is_numeric($str) AND !is_string($str))
        return false;
    //正由规则变量
    $match = '';
    //filter 条件
    if($filter!=''){
        $filter = My::explode(',',$filter);
        if(is_array($filter)){
            //英文字母
            if(in_array('e',$filter))
                $match .= 'a-zA-Z';
            //数字
            if(in_array('n',$filter))
                $match .= '0-9';
            //中文
            if(in_array('c',$filter))
                $match .= '\x{4e00}-\x{9fa5}';
        }
    }
    //其它正则特殊字符
    if($other!='')
        $match .= $other;
    //验证正则规则
    if($match!='' AND !preg_match('/^['.$match.']+$/u', $str))
        return false;
    return true;
};

 /**
 * json_decode ：json解码
 * @param string $str 等解码字符串
 * @return array
 */
function decodeJson($str=''){
    if(!$str OR !is_string($str)) return $str;
    return json_decode($str,true);
}

/**
 * json_encode ：不转义中文字符和\/的 json 编码方法
 * @param array $arr 待编码数组
 * @return string
 */
function encodeJson($arr='') {
    if(!is_array($arr))
        return $arr;
    // if(!function_exists('encodeHtml')){
    //     function encodeHtml(&$str){
    //         $str = My::encodeHtml($str,true);
    //     }
    // }
    // array_walk_recursive($arr,'encodeHtml');
    if(version_compare(PHP_VERSION, '5.4.0', '<')) {
        $str = str_replace ( "\\/", "/", json_encode ( $arr ) );
        $search = "#\\\u([0-9a-f]{4})#ie";
        if (strpos ( strtoupper(PHP_OS), 'WIN' ) === false) {
            $replace = "iconv('UCS-2BE', 'UTF-8', pack('H4', '\\1'))";//LINUX
        } else {
            $replace = "iconv('UCS-2', 'UTF-8', pack('H4', '\\1'))";//WINDOWS
        }
        $result = preg_replace($search, $replace, $str);
    }
    //PHP 5.4+ 有自带的不编码中文函数
    else{
        $result = json_encode($arr, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    }
    return $result;
}

/**
 * log ：存储日记
 * @param string $str 等解码字符串
 * @return array
 */
function log_record($content){
	$folder = date("Y-m-d",time());//文件夹名
	$file = date("Y-m-d H",time()).'.txt';//文件夹名
	$path = './Data/Log/Service/';
	$folder_path = $path.$folder;
	$dir = iconv("UTF-8", "GBK", $folder_path);
	if (!file_exists($dir))
        mkdir ($dir,0777,true);
    $file_path = $folder_path.'/'.$file;
    error_log($content,3,$file_path);
    return true;
}

/**
* 解析json串
* @param type $json_str
* @return type
*/
function analyJson($json_str) {
	$json_str = str_replace('＼＼', '', $json_str);
	$out_arr = array();
	preg_match('/{.*}/', $json_str, $out_arr);
	if (!empty($out_arr)) {
	$result = json_decode($out_arr[0], TRUE);
	} else {
	return FALSE;
	}
	return $result;
}
//	运行所有的worker Worker::runAll();


Worker::runAll();
